import Recorder from 'recorder-core';
import { message } from 'antd';

import 'recorder-core/src/engine/mp3';
import 'recorder-core/src/engine/mp3-engine';

/**
 * 依赖第三方，兼容性更好，文件可设置压缩格式，录音效果使用wave的扩展，显示波形
 */

const formatTime = timestamp => {
    const seconds = parseInt(timestamp / 1000, 10);

    const s = parseInt(seconds % 60, 10);
    const m = parseInt((seconds / 60) % 60, 10);
    const h = parseInt((seconds / 3600) % 24, 10);

    const ary = [];
    ary.push(h < 10 ? `0${h}` : h);
    ary.push(m < 10 ? `0${m}` : m);
    ary.push(s < 10 ? `0${s}` : s);

    return ary.join(':');
};

class AudioRecorder {
    rec;

    wave;

    durationDom;

    currentBlob;

    currentDuration;

    option = {
        audio: null,
        success: null
    };

    /** 调用open打开录音请求好录音权限* */
    recOpen = callback => {
        const { success } = this.option;

        // 每一次录音都要新建一个实例，详见close
        this.rec = Recorder({
            type: 'mp3',
            sampleRate: 16000,
            bitRate: 16, // mp3格式，指定采样率hz、比特率kbps，其他参数使用默认配置；注意：是数字的参数必须提供数字，不要用字符串；需要使用的type类型，需提前把格式支持文件加载进来，比如使用wav格式需要提前加载wav.js编码引擎
            // eslint-disable-next-line @typescript-eslint/no-unused-vars
            onProcess: (buffers, powerLevel, bufferDuration, bufferSampleRate, newBufferIdx, asyncEnd) => {
                // 录音实时回调，大约1秒调用12次本回调
                // 可利用extensions/MediaStreamRecorderMediaStreamRecorder.js扩展实时绘制波形
                // 可利用extensions/sonic.js扩展实时变速变调，此扩展计算量巨大，onProcess需要返回true开启异步模式
                this.currentDuration = bufferDuration;
                if (this.durationDom) {
                    this.durationDom.innerHTML = formatTime(bufferDuration);
                }
                if (this.wave) {
                    this.wave.input(buffers[buffers.length - 1], powerLevel, bufferSampleRate); // 输入音频数据，更新显示波形
                }
            },
            audioTrackSet: { noiseSuppression: false, echoCancellation: false } // 关闭降噪，录制回音
        });

        this.rec.open(
            () => {
                // 打开麦克风授权获得相关资源
                // rec.start() 此处可以立即开始录音，但不建议这样编写，因为open是一个延迟漫长的操作，通过两次用户操作来分别调用open和start是推荐的最佳流程
                if (success) success();
                if (callback) callback();
            },
            msg => {
                // 用户拒绝未授权或不支持
                // dialog&&dialog.Cancel(); 如果开启了弹框，此处需要取消
                message.error(`无法录音: 请确认录音授权已开启(${msg})`);
                // console.log(`${isUserNotAllow ? 'UserNotAllow，' : ''}无法录音:${msg}`);
            }
        );
    };

    /**
     * 成功后的回调
     * @callback successCallback
     */

    /**
     * 录音初始化配置函数
     * @param {Object} opt - 初始化配置
     * @param {successCallback} opt.success - open成功后的回调
     * @param {string} opt.waveSelector - 波形dom的css选择器
     * @param {string} opt.durationSelector - 倒计时dom的css选择器
     * @param {Object} opt.audio - audio的dom实例
     */

    recInitialize = (opt = {}) => {
        const { success, audio, waveSelector, durationSelector } = opt;
        if (success) this.option.success = success;
        if (waveSelector) this.wave = Recorder.WaveView({ elem: waveSelector }); // 创建wave对象
        if (durationSelector) this.durationDom = document.querySelector(durationSelector);
        // 绑定dom元素
        if (audio) {
            this.option.audio = audio;
            this.option.audio.controls = true;
        }
    };

    /** 开始录音* */
    recStart = (callback = () => {}) => {
        this.recOpen(() => {
            this.rec.start();
            callback();
        });
    };

    /** 结束录音* */
    recStop = (callback = () => {}, error = () => {}) => {
        if (!this.rec) return;
        this.rec.stop(
            (blob, duration) => {
                const blobUrl = (window.URL || window.webkitURL).createObjectURL(blob);
                console.log(blob, (blobUrl, `时长:${duration}ms`));
                this.rec.close(); // 释放录音资源，当然可以不释放，后面可以连续调用start；但不释放时系统或浏览器会一直提示在录音，最佳操作是录完就close掉
                this.rec = null;

                // 简单利用URL生成播放地址，注意不用了时需要revokeObjectURL，否则霸占内存
                if (this.option.audio) {
                    this.option.audio.src = blobUrl;
                    this.option.audio.load();
                }

                this.currentBlob = blob;
                callback();
            },
            msg => {
                console.log(`录音失败:${msg}`);
                this.rec.close(); // 可以通过stop方法的第3个参数来自动调用close
                this.rec = null;
                error();
            }
        );
    };

    recPlay = () => {
        if (this.option.audio) {
            this.option.audio.play();
        }
    };

    getBlob = () => this.currentBlob;

    getRecDuration = () => formatTime(this.currentDuration);

    destroy = () => {
        if (!this.rec) return;
        this.rec.close(); // 释放录音资源，当然可以不释放，后面可以连续调用start；但不释放时系统或浏览器会一直提示在录音，最佳操作是录完就close掉
        this.rec = null;
    };
}

export default AudioRecorder;

// export { recInitialize, recStart, recStop, recPlay, getBlob, getRecDuration, destroy };
